#include "selector.hpp"
#include <string.h>
#include <iterator>
#include "stdafx.h"
using namespace std;

selector::selector(){
	memset( &tvspec , 0 , sizeof( struct timespec) );
}

selector::selector( struct timespec timeout ){
	tvspec = timeout;
}

BOOL
selector::set_fd( selector_item * item_p ){
	item_list.push_back( item_p );
	return TRUE;
}

BOOL 
selector::del_fd( selector_item * item_p ){

	if( NULL == item_p ){
		SAY(DP_DEBUG,"del_fd: item_p is NULL\n");
		return FALSE;
	}

	list< selector_item * >::iterator iter;

	for( iter = item_list.begin() ; iter != item_list.end() ; iter++ ){

		selector_item * old_item_p = *iter;

		if( old_item_p == item_p ){

			item_list.erase( iter );

			break;
		}
	}
	return TRUE;
}

BOOL
selector::set_timeout( struct timespec timeout ){
	tvspec = timeout;
	return TRUE;
}

int 
selector::select(){
reselect:
	int ret=0 , maxfd=0 , i=0;

	FD_ZERO( &fds );

	list <selector_item * >::iterator iter;

	for( iter=item_list.begin() ; iter!=item_list.end() ; iter++ ){
		int fd = (*iter)->sock.m_nSock;
		if( fd < 0 ){
			continue;
		}
		FD_SET( fd , &fds );
		SAY( DP_DEBUG , "fd is %d\n" , fd );
		maxfd = maxfd > fd ? maxfd : fd ;
	}
	SAY( DP_DEBUG , "before pselect\n");
	ret = pselect( maxfd + 1, &fds, NULL, NULL, &tvspec, NULL );
	SAY( DP_DEBUG , "after pselect\n");

	if( 0 == ret ){ //timeout
		SAY(DP_DEBUG, "pselect time out!\n");

	}else if( 0 > ret ){ //select error 

		if( errno == EINTR || errno == EAGAIN){
			goto reselect;
		}

		SAY( DP_DEBUG , "errno:%d , %s\n" , errno , strerror(errno) );

		for( iter = item_list.begin() ; iter != item_list.end() ; iter ++ ){

			int fd = (*iter)->sock.m_nSock;

			if( ( fd >=0 ) && (valid_fd( fd ) < 0 ) ){

				SAY(DP_DEBUG, "pselect error:%s fd:%d\n" , strerror(errno) , fd );
				(*iter)->action( -1 , NULL );
			}
		}

	}else{ 

		for( iter=item_list.begin() ; iter !=item_list.end() ; iter ++ ,i++){

			int fd = (*iter)->sock.m_nSock;
			if( fd < 0 ){	
				continue;
			}
			if( FD_ISSET( fd , &fds ) ){

				(*iter)->action( 0 , NULL );
			}
		}
	}
	return ret;
}

void 
selector::select_alway( int condition ){
	while( condition ){
		select();
	}
}
